<?php

/** Represents an artist and provides different methods to query artist information.
 *
 * @package	php-lastfm-api
 * @author  Felix Bruns <felixbruns@web.de>
 * @version	1.0
 */
class Lastfm_Artist extends Lastfm_Media {

    /** Artist is streamable.
     *
     * @var     boolean
     * @access	private
     */
    private $streamable;
    /** Similar artists.
     *
     * @var	array
     * @access	private
     */
    private $similar;
    /** Artist tags.
     *
     * @var	array
     * @access	private
     */
    private $tags;
    /** The artists biography.
     *
     * @var	array
     * @access	private
     */
    private $biography;
    /** Stores a similarity value.
     *
     * @var	float
     * @access	private
     */
    private $match;

    /** Create an Artist object.
     *
     * @param string	$name		Name of this artist.
     * @param string	$mbid		MusicBrainz ID of this artist.
     * @param string	$url		Last.fm URL of this artist.
     * @param array	$images		An array of cover art images of different sizes.
     * @param boolean	$streamable	Is this artist streamable?
     * @param integer	$listeners	Number of listeners of this artist.
     * @param integer	$playCount	Play count of this artist.
     * @param array	$tags		An array of tags of this artist.
     * @param array	$similar	An array of similar artists.
     * @param string	$biography	Biography of this artist.
     * @param float	$match		Similarity value.
     *
     * @access	public
     */
    public function __construct($name, $mbid, $url, array $images, $streamable, $listeners, $playCount, array $tags, array $similar, $biography, $match) {
        parent::__construct($name, $mbid, $url, $images, $listeners, $playCount);

        $this->streamable = $streamable;
        $this->tags = $tags;
        $this->similar = $similar;
        $this->biography = $biography;
        $this->match = $match;
    }

    /** Returns if this artists is streamable.
     *
     * @return	boolean	true if this artist is streamable, otherwise false.
     * @access	public
     */
    public function isStreamable() {
        return $this->streamable;
    }

    /** Returns similar artists.
     *
     * @return	array	An array of similar artists.
     * @access	public
     * @see	getSimilar
     */
    public function getSimilarArtists() {
        return $this->similar;
    }

    /** Returns artist tags.
     *
     * @return	array	An array of Tag objects.
     * @access	public
     * @see	Tag
     */
    public function getArtistTags() {
        return $this->tags;
    }

    /** Returns the artists biography.
     *
     * @return	string	A biography text.
     * @access	public
     */
    public function getBiography() {
        return $this->biography;
    }

    /** Returns similarity value.
     *
     * @return	float	A floating-point value from 0.0 to 1.0.
     * @access	public
     */
    public function getMatch() {
        return $this->match;
    }

    /** Get a list of upcoming events for this artist. Easily integratable into calendars, using the ical standard (see feeds section below).
     *
     * @param	string	$artist	The artist name in question. (Required)
     * @param	integer	$limit	Limit the number of events returned at one time. Default (maximum) is 30. (Optional)
     * @param	integer	$page	Scan into the results by specifying a page number. Defaults to first page. (Optional)
     * @return	array			An array of Event objects.
     * @see	Event
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function getEvents($artist, $limit, $page) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.getEvents', array(
                    'artist' => $artist,
                    'limit' => $limit,
                    'page' => $page
                ));

        $events = array();

        foreach ($xml->children() as $event) {
            $events[] = Lastfm_Event::fromSimpleXMLElement($event);
        }
        return array('totalPages' => (int) $xml->attributes()->totalPages, 'events' => $events);
    }

    /** Get the metadata for an artist on last.fm. Includes biography.
     *
     * @param	string	$artist	The artist name in question. (Optional)
     * @param	string	$mbid	The MusicBrainz ID for the artist. (Optional)
     * @param	string	$lang	The language to return the biography in, expressed as an ISO 639 alpha-2 code. (Optional)
     * @return	Artist  An Artist object.
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function getInfo($artist, $mbid = null, $lang = null) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.getInfo', array(
                    'artist' => $artist,
                    'mbid' => $mbid,
                    'lang' => $lang
                ));

        return Lastfm_Artist::fromSimpleXMLElement($xml);
    }

    /** Checks if an artist exists on last.fm.
     *
     * @param	string	$artist	The artist name in question. (Optional)
     * @return	Artist  An Artist object.
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function isValid($artist) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.getInfo', array(
                    'artist' => $artist
                ));
        if($xml->mbid == "")
            throw new Lastfm_Error ('The artist you supplied could not be found', 6);
        return Lastfm_Artist::fromSimpleXMLElement($xml);
    }

    /** Get all the artists similar to this artist.
     *
     * @param	string	$artist	The artist name in question. (Required)
     * @param	string	$limit	Limit the number of similar artists returned. (Optional)
     * @return	array	An array of Artist objects.
     * @see		getSimilarArtists
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function getSimilar($artist, $limit = null) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.getSimilar', array(
                    'artist' => $artist,
                    'limit' => $limit
                ));
        $searchArtist = $artist;
        $artists = array();

        foreach ($xml->children() as $artist) {
            $artists[] = Lastfm_Artist::fromSimpleXMLElement($artist);
        }

        return array("artist" => $searchArtist, "similar" => $artists);
    }

    /** Get the top albums for an artist on last.fm, ordered by popularity.
     *
     * @param	string	$artist	The artist name in question. (Required)
     * @param	integer	$limit	Limit the number of albums returned at one time. Default (maximum) is 30. (Optional)
     * @return	array   An array of Album objects.
     * @see		Album
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function getTopAlbums($artist, $limit = null) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.getTopAlbums', array(
                    'artist' => $artist,
                    'limit' => $limit
                ));

        $albums = array();

        foreach ($xml->children() as $album) {
            $albums[] = Lastfm_Album::fromSimpleXMLElement($album);
        }

        return $albums;
    }

    /** Search for an artist by name. Returns artist matches sorted by relevance.
     *
     * @param	string	$artist	The artist name in question. (Required)
     * @param	integer	$limit	Limit the number of artists returned at one time. Default (maximum) is 30. (Optional)
     * @param	integer	$page	Scan into the results by specifying a page number. Defaults to first page. (Optional)
     * @return	PaginatedResult	A PaginatedResult object.
     * @see		PaginatedResult
     *
     * @static
     * @access	public
     * @throws	Error
     */
    public static function search($artist, $limit = null, $page = null) {
        $xml = Lastfm_Caller_Factory::getDefaultCaller()->call('artist.search', array(
                    'artist' => $artist,
                    'limit' => $limit,
                    'page' => $page
                ));

        $artists = array();

        foreach ($xml->artistmatches->children() as $artist) {
            $artists[] = Lastfm_Artist::fromSimpleXMLElement($artist);
        }

        $opensearch = $xml->children('http://a9.com/-/spec/opensearch/1.1/');

        return new Lastfm_PaginatedResult(
                Lastfm_Util::toInteger($opensearch->totalResults),
                Lastfm_Util::toInteger($opensearch->startIndex),
                Lastfm_Util::toInteger($opensearch->itemsPerPage),
                $artists
        );
    }

    /** Create an Artist object from a SimpleXMLElement object.
     *
     * @param	SimpleXMLElement	$xml	A SimpleXMLElement object.
     * @return	Artist				An Artist object.
     *
     * @static
     * @access	public
     * @internal
     */
    public static function fromSimpleXMLElement(SimpleXMLElement $xml) {
        $images = array();
        $tags = array();
        $similar = array();

        /* NOTE: image, image_small... this sucks! */

        if ($xml->image) {
            if (count($xml->image) > 1) {
                foreach ($xml->image as $image) {
                    $images[Lastfm_Util::toImageType($image['size'])] = Lastfm_Util::toString($image);
                }
            } else {
                $images[Lastfm_Media::IMAGE_LARGE] = Lastfm_Util::toString($image);
            }
        }

        if ($xml->image_small) {
            $images[Lastfm_Media::IMAGE_SMALL] = Lastfm_Util::toString($xml->image_small);
        }

        if ($xml->tags) {
            foreach ($xml->tags->children() as $tag) {
                $tags[] = Lastfm_Tag::fromSimpleXMLElement($tag);
            }
        }

        if ($xml->similar) {
            foreach ($xml->similar->children() as $artist) {
                $similar[] = Lastfm_Artist::fromSimpleXMLElement($artist);
            }
        }

        return new Lastfm_Artist(
                Lastfm_Util::toString($xml->name),
                Lastfm_Util::toString($xml->mbid),
                Lastfm_Util::toString($xml->url),
                $images,
                Lastfm_Util::toBoolean($xml->streamable),
                ($xml->stats) ? Lastfm_Util::toInteger($xml->stats->listeners) : 0,
                ($xml->stats) ? Lastfm_Util::toInteger($xml->stats->playcount) : 0,
                $tags,
                $similar,
                ($xml->bio) ? Lastfm_Util::toString($xml->bio->summary) : "", // TODO: Biography object
                Lastfm_Util::toFloat($xml->match)
        );
    }

}

